﻿using System;
using System.Collections.Generic;

namespace Common.Logging.Loupe
{
    /// <summary>
    /// This class is a wrapper that provides Cached ToString()
    /// functionality on an Enum and also quick lookups and a TryParse
    /// implementation.  It is not necessarily on .NET 4.0 but is used
    /// so we can compile against 3.5 and older frameworks.
    /// </summary>
    /// <typeparam name="T">The type.</typeparam>
    public static class ParsableEnum<T> where T : struct
    {
        /// <summary>
        /// Allows names to be mapped to values
        /// </summary>
        static Dictionary<string, T> _nameToValueLookup;

        /// <summary>
        /// Allows values to be mapped to names
        /// </summary>
        static Dictionary<T, string> _valueToNameLookup;

        /// <summary>
        /// Called when the first instance of ParsableEnum (of T) is accessed"/>
        /// </summary>
        static ParsableEnum()
        {
            Type targetType = typeof(T);
            
            // Initialize lookups     
            _nameToValueLookup = new Dictionary<string, T>();
            _valueToNameLookup = new Dictionary<T, string>();

            var values = Enum.GetValues(targetType);
            
            foreach (var value in values)
            {
                string name = Enum.GetName(targetType, value);
                _valueToNameLookup.Add((T) value, name);
                _nameToValueLookup.Add(name, (T)value);
            }
        }

        /// <summary>
        /// Tries to parse the provided name and output the value.
        /// </summary>
        /// <param name="name">The name to parse.</param>
        /// <param name="value">The output value.</param>
        /// <returns>true if possible, false otherwise.</returns>
        public static bool TryParse(string name, out T value)
        {
            lock (_nameToValueLookup)
            {
                return _nameToValueLookup.TryGetValue(name, out value);
            }
        }

        /// <summary>
        /// Gets the string name for the provided value.
        /// </summary>
        /// <param name="value">Requested value.</param>
        /// <returns>The value.</returns>
        public static string ToCachedString(T value)
        {
            lock (_valueToNameLookup)
            {
                return _valueToNameLookup[value];
            }
        }
    }
}
